YFX Exporter
repo
Overview
シーン上のモデルのFBXエクスポート出力処理時に、モディファイアの適用やオブジェクト統合などを行うプラグインです。モディファイアの適用やオブジェクト統合は別プロセスで行われるため、シーン上のファイルは破壊されません。
Requirement
ミラーモディファイアついたオブジェクトをエクスポートするとシェイプキーが消える
これが治るだけでもこのアドオンは有用
Transformの問題
BlenderのモデルをUnityに持っていくと倒れてしまう問題の解決方法と、FBXの設定を解説。
類似アドオン
Functional Specitification
選択したCollectionごとにマージする
Collectionがネストするパターンに対応するために再帰的な処理が必要
AutoSmooth、法線について
Blender 4.1待ち
Armature以外を適用する
無効なモディファイアは削除
Constraintを適用
カーブをメッシュへ変換
背反としてウェイトがのらないので警告はOFF
Apply All Transform
オブジェクト原点をワールド座標原点に設定
これはよくわからんので要調査
Merge機能が動くためのチェック
Validatorの結果を自動修正できる?
Separate
左右対称シェイプキー(_LR)を_L, _Rに分割
「まばたき」→「ウインク」もあるといいかも
Sort
シェイプキーの並び替え
MMD
モディファイア適用後に変形ボーン以外を削除
Release用
すべての処理を現在のシーンで行わない(background処理)
デバッグ用に現在のシーンを破壊して実行するモードもあり?
複数のFBXにエクスポートできるようにする?
「表示状態のオブジェクトを出力」に背反する
これがあるので不採用かな
Limitation
(保留)リンク複製されたオブジェクトは問題ない?
ひとまずシングルユーザ化しておく(データ、オブジェクト)
オブジェクトが複数のCollectionに所属している場合には対応しない
Text, Surfece, Curveのシェイプキーには対応しない
Functional Design
Settings
export_settings : ExportSettings
// is_subprocess : Bool // process間通信するかの判定用(Deprecated)
// updater_settings : UpdaterSettings #将来用 ExportSettings
collections : SEQUENCE<CollectionSetting>
collection_index:Int
run_in_background : Bool (default = True) debug
fbx_export_settings :YFX_EXPORTER_PG_fbx_export_settings
export_path : String
temp_path : String
CollectionSetting
collection_ptr : POINTER<bpy.types.collection>
enable_merge : Bool
transform_settings : TransformSettings
shapekey_settings : CollectionShapeKeySettings
warning_settings : WarningSettings
vertex_group_settings : VertexGroupSettings
WarningSettings
check_warning : Bool
check_exist_armature : Bool
check_vertices_with_no_weights : Bool
ShapekeySetting
name:str
CollectionShapeKeySettings
separate_shapekey : Bool
separate_mmd_shapekey : Bool
sort_shapekey:bool
shapekeys : list (ShapekeySetting)# シェイプキーソート用機能
shapekey_index : int
TransformSettings
apply_all_transform : Bool
VertexGroupSettings
delete_vertex_group : Bool
方針
できるだけCollectionごとにSettingできるように持つ
ネストしたCollectionの場合、親が優先される
ネストしたCollectionを検出して警告?
Export Process
Validation
Warning
--- ここから非同期処理? ---
AutoFix
インスタンスを実体化
bpy.ops.object.duplicates_make_real
ローカル化
シングルユーザー化
bone(Armature)のTransformをリセット
Modifier, Object Constraintとかがずれる?
Object Constraintを適用
Curve, Text, SurfeceをMeshに変換
Modifierを適用(keep shape keys)
Merge Object
1. オブジェクトをマージ
ネストしてるCollectionの場合は一番親階層のコレクションのみ有効
2. オブジェクト名をCollection名にリネーム
Transform Apply
Separate Shapekey
各オブジェクトの原点基準で分ける
↑がうれしいケースが思いつかないのでワールド原点基準のがいいか
ワールド原点を基準に左右で分ける
Delete unused vertex group
zero weight
non armature
Delete object
FBX Export
方針
前処理(Validation, Warning check)はforegroundでやる
前処理だけやるケースを想定
Code
Namespace
YFX_EXPORTER_*
yfx_exporter_*
「YF_MERGE_EXPORTER_」はかなり長い気がするので変えた
Lint
ignore rule
"ARG001" unused-function-argument
"ARG002" unused-function-argument
Blender APIに対する警告
"ANN101" missing-type-self
ANN102 missing-type-cls
self,clsのtypingは冗長
PLR0913 too-many-arguments
Blender APIに対する警告
"N801" invalid-class-name
blenderの命名規則が逸脱する
"N999"
invalid-module-name
Checks for module names that do not follow the snake_case naming convention or are otherwise invalid.
"D"
pydocstyle(D)
一旦保留中。。。
保留
N999 パッケージ名の警告 キャメルケースであること
YFX_Exporterは逸脱
本当はキャメルケースにすべきか
Background参考
シェイプキー付きオブジェクトのApply
FBX Export
MetaProgrammingで生成できる?
sys.modules["io_scene_fbx"].ExportFBXでクラス取得できるからこれを使える?
inspect.get_annotations(sys.modules["io_scene_fbx"].ExportFBX)
getattr(sys.modules["io_scene_fbx"].ExportFBX,'__annotations__',None)
export設定
結構変わってる
use_space_transform
Apply global space transform to the object rotations. When disabled only the axis space is written to the file and all object transforms are left as-is
グローバル空間変換をオブジェクトの回転に適用します。 無効にすると、軸スペースのみがファイルに書き込まれ、すべてのオブジェクト変換はそのまま残されます。
prioritize_active_color
アクティブなカラーが最初にエクスポートされることを確認してください。 他のソフトウェアでは最初の色属性以外の色属性を破棄できる場合があるため、これは重要である可能性があります。
separate shapekey
LazyShapekey op_other.py
真ん中は半分だけマージする
浮動小数対策で中心判定のマージンを設ける epsilon
blenderのeps : import sys, sys.float_info.epsilon = 2.220446049250313e-16
命名
joiner
modifier
modifier_applier
applier
Test
Test Case
1_Merge Test
Merge
2段以上のコレクションが統合できる
非表示がMergeされない
Merge対象外がMergeされない
リンク複製したオブジェクト
複数のMerge対象コレクションに所属しているオブジェクト(error)
Convert Object
メッシュに変換できること
Modifierが適用できること
Object Constraintが適用できること
Apply Modifier
モディファイアが適用できること
アーマチュアモディファイアを適用しないこと
シェイプキーがあるオブジェクトのモディファイアを適用できること
依存関係のあるモディファイア
モディファイアが参照するオブジェクトのTransformを適用する場合、モディファイアの振る舞いを変えずにモディファイアが適用されること
ViewPort Offにしたモディファイアが適用されずに削除されること
Apply Constraint
Object Constraintが適用できること
Transform
Transformが適用できること
2_Normal Test
0_VariableNormal
様々な法線設定でテスト
1_AutoSmooth
AutoSmoothの角度違い
table:testcase
name AutoSmooth CustomN Shade Modifier
0(active) 30 no auto no
1 90 no auto no
2_AutoSmooth
AutoSmoothOFF + カスタム法線ありでAutoSmoothのついていない方がアクティブになるもの
table:testcase
name AutoSmooth CustomNormal Shade Modifier
0(active) off no flat no
1 on yes auto no
2_AutoSmooth
カスタム法線が入っているのにAutoSmoothがOFFにされている(無効なカスタム法線)
table:testcase
name AutoSmooth CustomNormal Shade Modifier comment
0(active) on(90) no auto no
1 off yes flat no 無効なカスタム法線
3_エラー推定
Blenderを日本語設定にしてテスト
日本語名のオブジェクト、コレクション名でテスト
Issue
(2024/10/21)ウェイトペイントモードのオブジェクトが存在するとエラーとなる
エラーが出たらこれを疑いたい
code:err
Traceback (most recent call last):
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\yfx_exporter\process.py", line 76, in <module>
run_export_process(context)
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\yfx_exporter\process.py", line 16, in run_export_process
export(context, settings)
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\yfx_exporter\exporter.py", line 101, in export
apply_all_objects(context)
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.2\scripts\addons\yfx_exporter\exporter.py", line 43, in apply_all_objects
bpy.ops.object.select_all(action="DESELECT")
File "D:\apps\Blender\stable\blender-4.2.2-lts+stable.c03d7d98a413\4.2\scripts\modules\bpy\ops.py", line 109, in __call__
ret = _op_call(self.idname_py(), kw)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: Operator bpy.ops.object.select_all.poll() failed, context is incorrect
シェイプキーのあるモディファイア適用に失敗する(シェイプキーの統合で失敗する)
code:error
Python: Traceback (most recent call last):
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.1\scripts\addons\yfx_exporter\operators.py", line 271, in execute
start_foreground_export(context)
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.1\scripts\addons\yfx_exporter\process.py", line 20, in start_foreground_export
run_export_process(context)
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.1\scripts\addons\yfx_exporter\process.py", line 16, in run_export_process
export(context, settings)
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.1\scripts\addons\yfx_exporter\exporter.py", line 101, in export
apply_all_objects(context)
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.1\scripts\addons\yfx_exporter\exporter.py", line 52, in apply_all_objects
main_apply_modifiers(obj)
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.1\scripts\addons\yfx_exporter\modifier.py", line 97, in main_apply_modifiers
apply_modifiers_with_shapekeys(obj)
File "C:\Users\user\AppData\Roaming\Blender Foundation\Blender\4.1\scripts\addons\yfx_exporter\modifier.py", line 74, in apply_modifiers_with_shapekeys
obj.data.shape_keys.key_blocksi.name = shapekeys_blocksi.name ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^
IndexError: bpy_prop_collectionindex: index 3 out of range, size 3 https://gyazo.com/76311c7fd22bd4e84ee661a8f2394b8e
原因:縮小(Shrink)のシェイプキーオブジェクトのモディファイア適用時に頂点の数が変わってしまう(Mirrorモディファイアの適用時に頂点がマージされてしまう)
暫定:
Mirrorモディファイアの「Merge」で頂点数が変わらないように気を付けてシェイプキーを作る
Weldに置き換えてDistanceを小さくする
恒久対策
このように頂点数が変わってもシェイプキーが転送できるように処理を変える?
原理的にシェイプキーありモディファイアの適用が難しい。。。
モディファイア適用後のBlender保存時に「Error: Shapekey KEKey.003 has an invalid 'from' pointer (0000000000000000), it will be deleted」が表示される
再現条件:シェイプキー + モディファイアを含むObjectがあるとき
Blenderのバグ説はちょっとある
・手動でやると再現しない。
・blendshape donorのオブジェクトを削除しないとエラー発生しない
https://gyazo.com/dee3720876fbadba394a138336c9deb0
解決法:
オブジェクト削除を「bpy.ops.object.delete」でやるように修正
performanceが悪化するかも
Shapekey消してから消せばいい?(未確認)
code:remove.py
def remove_object(obj: bpy.types.Object) -> None:
bpy.context.view_layer.objects.active = obj
bpy.ops.object.select_all(action="DESELECT")
obj.select_set(state=True)
bpy.ops.object.delete(use_global=False, confirm=False)
# 以前の処理↓
# mesh_data = obj.data
# bpy.data.objects.remove(obj)
# bpy.data.meshes.remove(mesh_data)
Shapekeyの並び替えを変えるのが結構大変
結局以下のようなスクリプトで並び変えている。。。
code:shapekey_sort.py
import bpy
collections = bpy.context.scene.yfx_exporter_settings.export_settings.collections
target_collection = next((c for c in collections if c.collection_ptr.name == 'Body'), None)
shapekeys = target_collection.shapekey_settings.shapekeys
# sort
shapekey_names = LIPSYNC ---','vrc.v_sil','vrc.v_PP','vrc.v_FF','vrc.v_TH','vrc.v_DD','vrc.v_kk','vrc.v_CH','vrc.v_SS','vrc.v_nn','vrc.v.RR','vrc.v_aa','vrc.v_E','vrc.v_ih','vrc.v_oh','vrc.v_ou','--- BROW ---','--- EYES ---','まばたき','--- MOUSE ---','あ','い','う','え','お','口角上げ','口横広げ','口角下げ','口すぼみ','歯閉じ','歯開き','上歯前','下歯前','上歯後','下歯後','舌上','舌下','舌出','舌奥','舌巻','--- PARTS ---'
len_shapekeys = len(shapekeys)
for name in shapekey_names:
idx = shapekeys.find(name)
if idx < 0:
continue
shapekeys.move(idx, len_shapekeys - 1) # move to bottom
工数
94.95h
table:task
parent ラベル quotient(quotient(sum Σ 消費時間60())60())
YUUFYU-2 Coding 84.1
YUUFYU-2 Designing 3.95
YUUFYU-2 Documentation 1.7
YUUFYU-2 Management 0.25
YUUFYU-2 Testing 4.95